#!/usr/bin/env python3

import os
import sys
import random
import pygame
import threading

def run(f, interval=0.1, args=None, kwargs=None):
    """
    定时器封装
    """
    t = threading.Timer(interval, f, args, kwargs)
    t.start()
    return t

def getColor(color=None):
    """
    转换颜色及返回随机颜色
    """
    if color == None:
        return (random.randint(0, 255),
                random.randint(0, 255),
                random.randint(0, 255))
    elif type(color) == tuple:
        return color
    return color >> 16 & 0xFF, color >> 8 & 0xFF, color & 0xFF

def drawPixel(x, y, color):
    """
    画点
    """
    screen = pygame.display.get_surface()
    #   print(color, screen)
    pygame.draw.rect(screen, color, (x * 10, y * 10, 10, 10))

def drawCircle(x, y, r, color):
    """
    画圆
    """
    screen = pygame.display.get_surface()
    pygame.draw.circle(screen, color, (x * 10, y * 10), r)

def createConvas(r, c):
    """
    画布创建
    """
    convas = list(range(c))
    for x in convas:
        convas[x] = list(range(c))
    return convas

def initConvas(convas, row, col):
    """
    画布初始化
    """
    for r in range(row):
        for c in range(col):
            if r == 0 or c == 0 or r == row - 1 or c == col - 1:
                convas[r][c] = '#'
            else:
                convas[r][c] = ' '

    return convas

def showConvas(ball):
    """
    刷新画布
    """
    convas = ball['convas']

    ch = [x['ch'] for x in ball['balls']]
    color = [x['color'] for x in ball['balls']]

    for r in range(ball['row']):
        for c in range(ball['col']):
            point = convas[r][c]
            if point in ch:
                drawCircle(c, r, 10, color[ch.index(point)])
            else:
                drawPixel(c, r, 0)

    pygame.display.update()

def draw(convas, row, col, ball):
    """
    在画布上作画，画一个球
    """
    convas[ball['y']][ball['x']] = ball['ch']

def draws(ball):
    """
    画所有球
    """
    for i in range(ball['num']):
        draw(ball['convas'], ball['row'], ball['col'], ball['balls'][i])

def initBallDict(r=15, c=60, num=1, ball=None):
    """
    初始化弹球程序的数据
    """
    if not ball:
        ball = {}

    ball['row'] = r
    ball['col'] = c
    ball['convas'] = createConvas(r, c)
    ball['pause'] = False
    ball['num'] = num
    ball['balls'] = []

    for i in range(num):
        data = {}
        data['r'] = random.randint(10, 10)
        data['x'] = random.randint(1, ball['col'] - data['r'] - 1)
        data['y'] = random.randint(1, ball['row'] - data['r'] - 1)
        data['x_inc'] = random.choice([1, -1])
        data['y_inc'] = random.choice([1, -1])
        data['color'] = getColor()
        data['ch'] = random.choice('@*&%+-SABCDEFGI')

        ball['balls'].append(data)

    return ball

def ballProInit(row=48, col=64, num=1):
    """
    弹球程序的初始化操作
    """
    pygame.init()

    pygame.display.set_mode((col * 10, row *10))

    return initBallDict(row, col, num)

def ballProExit(ball):
    """
    弹球程序退出终端还原操作
    """
    ball['thread'].cancel()
    ball['thread'].join()
    pygame.quit()
    os._exit(0)

def move(row, col, ball):
    """
    一个弹球运动控制
    ball: 一个弹球的对象
    """
    if ball['x'] <= 0 or ball['x'] >= col - 1:
        ball['x_inc'] *= -1
        ball['color'] = getColor()

    if ball['y'] <= 0 or ball['y'] >= row - 1:
        ball['y_inc'] *= -1
        ball['color'] = getColor()

    ball['x'] += ball['x_inc']
    ball['y'] += ball['y_inc']

def moves(ball):
    """
    所有球的运动控制
    """
    for i in range(ball['num']):
        move(ball['row'], ball['col'], ball['balls'][i])

def ballRun():
    """
    弹球动画流程
    """
    if ball['pause']:
        return

    initConvas(ball['convas'], ball['row'], ball['col'])
    draws(ball)
    moves(ball)
    showConvas(ball)

    ball['thead'] = run(ballRun, 0.1)

def getInput(ball):
    """
    获取按键并且处理
    """
    while True:
        e = pygame.event.wait()
        if e.type == pygame.QUIT:
            break
        elif e.type == pygame.KEYDOWN:
            if e.key == pygame.K_ESCAPE or e.key == pygame.K_q:
                break
            elif e.key == pygame.K_SPACE:
                ball['pause'] = not ball['pause']
                ball['thead'] = run(ballRun)

if __name__ == "__main__":
    n = 10 if len(sys.argv) < 2 else int(sys.argv[1])
    ball = ballProInit(num=n)
    ball['thread'] = run(ballRun)
    getInput(ball)
    ballProExit(ball)
